#Now we are in the loader.bin,
#the loader place the kernel.bin at 0x10000-0x9FBFF ,
#then enter the protected mode ,
#at last ,place the kernel to the 0x100000-0x300000


.section .text 
.code16

  jmp Loader_Start




#---------------------------------------------;
#  Global variables.                          ;
#---------------------------------------------;
  #cgashowoffset range:0-3998
  artist:                     .ascii "                    \\(^oo^)/ Artist ,HalfGod(ChenWu)                    "
  cgashowoffset:              .int  0
  kernelname:                 .ascii "KERNEL  BIN"
  nokernel:                   .ascii "No Kernel!!"
  kernelnextsegment:          .word  KERNELFIRSTBASE
  kernelnextoffset:           .int  KERNELFIRSTOFFSET
  kernelparametersnextoffset: .int  KERNELPARAMETERSBUFFEROFFSET
  ardsnumber:                 .int  0
  getmemorysizeerrormessage:  .ascii "MemoryError" 
  getmemorysizesuccessmessage:.ascii "The Memory size is 0x"
  loaderprotectmodemessage:   .ascii "Artist enter the protect mode in the loader." #44bytes





.include "loader/KernelSize.tmp"




.align 8
  gdtbegin:                   .quad  0x0000000000000000
  gdtkernelcode:              .quad  0x00CF9A000000FFFF
  gdtkerneldata:              .quad  0x00CF92000000FFFF
  gdtcga:                     .quad  0x00C0920B80000002
  gdtend:                     .quad  0x0000000000000000

  .equ  GDTLENGTH,gdtend-gdtbegin


  gdtpointer:                 .word  GDTLENGTH-1
                              .int   gdtbegin

  .equ   SELECTORKERNELCODE,gdtkernelcode-gdtbegin
  .equ   SELECTORKERNELDATA,gdtkerneldata-gdtbegin
  .equ   SELECTORCGA       ,gdtcga       -gdtbegin


.include "loader/loader.h"





#----------------------------------------------------------------------------------------------------;
#                            Artist,Let's go!!!!!!!!!!!!!!!!!!!!!!                                   ;
#                                        HalfGod(ChenWu)                                             ;
#----------------------------------------------------------------------------------------------------;
.global Loader_Start

Loader_Start:
#------------------------------------;
#init the segment registers and stack;
#------------------------------------;
  movw %cs,%ax  
  movw %ax,%ds
  movw %ax,%es
  movw %ax,%ss
  movw $CGABASE,%ax
  movw %ax,%gs
  movl $LOADERSTACK,%esp
  movl $KERNELPARAMETERSCOUNTOFFSET,%eax
  movl $0,(%eax)
  movl $0,%eax
#Read the root entry directory       ;
#------------------------------------;
  pushw $ROOTENTRYBUFFEROFFSET
  pushw $ROOTENTRYBUFFERSEGMENT
  pushw $ROOTENTRYSECTORNUMBER
  pushw $ROOTENTRYSTARTSECTOR
  call  ReadSector
  addl  $8,%esp

#------------------------------------;
#To find the kernel.bin entry        ;
#------------------------------------;
  movl  $ROOTENTRYBUFFERFULLADDRESS,%esi
LABEL_SEARCH:
  movl  $KERNELNAMELENGTH,%ecx
  leal  kernelname,%edi
  cld
  repe  cmpsb
  je    LABEL_FIND
  andl  $0x0FFE0,%esi
  addl  $0x20,%esi
  cmpl  $ROOTENTRYBUFFEREND,%esi
  jg    LABEL_NOFIND
  jmp   LABEL_SEARCH
#-----------------------------------;
#Find the file entry.               ;
#-----------------------------------;
LABEL_FIND:
# Ok,we first push the first cluster serial number.
  pushw  15(%esi)
  pushw $FATBUFFEROFFSET
  pushw $FATBUFFERSEGMENT
  pushw $FATSECTORNUMBER
  pushw $FATSTARTSECTOR
  call  ReadSector
  addl  $8,%esp
#Let's get the first cluster serial number.
  popw  %ax

#--------------------------------------------------------------;
# We load the file to the LOADERBASEADDRESS:LOADEROFFSETADDRESS;
#--------------------------------------------------------------;
LABEL_LOAD:
  addw   $SECTOROFFSET,%ax
  pushw  kernelnextoffset
  pushw  kernelnextsegment
  pushw  $1
  pushw  %ax
  call   ReadSector
  addl   $8,%esp
  xorl   %ecx,%ecx
  movw   kernelnextsegment,%cx
  sall   $4,%ecx
  addl   kernelnextoffset,%ecx
  addl   $512,%ecx
  movw   %cx,kernelnextoffset
  movw   $0,%cx
  shrl   $4,%ecx
  movw   %cx,kernelnextsegment
  subw   $SECTOROFFSET,%ax
  movw   $3,%bx
  mulw   %bx
  movw   $2,%bx
  divw   %bx
  addw   $0x500,%ax
  andl   $0x0000FFFF,%eax
  movw   (%eax),%bx
  cmpw   $0,%dx
  je     LABEL_EVEN
  shrw   $4,%bx
  jmp    LABEL_ENDORNO
LABEL_EVEN:
  andw   $0x0FFF,%bx
LABEL_ENDORNO:
  cmpw   $0xFF7,%bx
  jae    LABEL_LOADED
  movw   %bx,%ax
  jmp    LABEL_LOAD

LABEL_LOADED:
    #The motor should be killed now.
    call   KillMotor
    #Clear the screen.
    call   ClearScreen
    #Go to the first line.
    call   PutReturn
    #Output the string to show the OS message.
    pushw  $70
    pushw  $0x0F
    pushl  $artist
    call   PutAttributeString
    addl   $8,%esp
    #Go to the second line.
    call   PutReturn
    #Output the message for memory size.
    pushw  $21
    pushw  $0x0F
    pushl  $getmemorysizesuccessmessage
    call   PutAttributeString
    addl   $8,%esp
#    jmp .
    #Get the ARDS of the memory .
    call   GetMemorySize
    #Find the last one place which can be used.Just to find the size 
    #of the memory.
    movw   ardsnumber,%cx
    cmpw   $0,%cx
    je     LABEL_GETMEMORYSIZEERROR
    movl   $0,%eax
 #   jmp .
    pushl  %eax
    pushl  %ebx
    pushl  %ecx
    pushl  %edx
    
LABEL_PLACEPARAMETERSARDS:
    cmpw   $0,%cx
    je     LABEL_PLACEPARAMETERSARDSEND
    subw   $1,%cx
    movb   $20,%al
    mulb   %cl
    addw   $MEMORYCHECKBUFFEROFFSET,%ax
#    jmp .
 #the eax contain the address of ARDS struct
    movl   kernelparametersnextoffset,%ebx
 #the ebx contain the parameters address
    movl   $KERNELPARAMETERSLABELRAMMAP,(%ebx)
#jmp . 
   movl   (%eax),%edx
    movl   %edx,4(%ebx)

    movl   8(%eax),%edx
    movl   %edx,8(%ebx)

    movl   16(%eax),%edx
    movl   %edx,12(%ebx)
    addl   $KERNELPARAMETERSSIZE,kernelparametersnextoffset
    movl   $KERNELPARAMETERSCOUNTOFFSET,%edx
    incl   (%edx)
   jmp    LABEL_PLACEPARAMETERSARDS
LABEL_PLACEPARAMETERSARDSEND:
    popl   %edx
    popl   %ecx
    popl   %ebx
    popl   %eax
#  jmp .   
LABEL_GOONFINDMAXMEMORY:
    subw   $1,%cx
    movb   $20,%al
    mulb   %cl
    addw   $MEMORYCHECKBUFFEROFFSET,%ax
    cmpl   $1,16(%eax)
    jne    LABEL_GOONFINDMAXMEMORY
    movl   (%eax),%ebx
    movl   8(%eax),%edx
    addl   %ebx,%edx
    #Now the edx contains the size of the memory.
    #Following the previous message,show the specific number.
    pushl  %edx
    call   PutFourBytesNumber
    popl   %edx
    pushl  %eax
    pushl  %ebx
    pushl  %ecx
    pushl  %edx
    movl   $KERNELPARAMETERSCOUNTOFFSET,%eax
    incl   (%eax)
    movl   kernelparametersnextoffset,%eax
    movl   $KERNELPARAMETERSLABELRAMSIZE,(%eax)
    movl   %edx,4(%eax)
    addl   $KERNELPARAMETERSSIZE,kernelparametersnextoffset
    movl   kernelparametersnextoffset,%edx
    movl   $KERNELPARAMETERSNEXTCONTAINER,%ebx
    movl   %edx,(%ebx)
    popl   %edx
    popl   %ecx
    popl   %ebx
    popl   %eax
    jmp    LABEL_GOTOPROTECTMODE
    jmp .
LABEL_GETMEMORYSIZEERROR:
    movw $getmemorysizeerrormessage,%ax
    movw %ax,%bp
    movw $11,%cx
    movw   $0x01301,%ax
    movw   $0x000C,%bx
    movb   $0,%dl
    int    $0x10
    jmp .
  
LABEL_NOFIND:
  movw   $nokernel,%ax
  movw   %ax,%bp
  movw   $11,%cx
  movw   $0x01301,%ax
  movw   $0x000C,%bx
  movb   $0,%dl
  int    $0x10
  jmp .
#------------------------------------------------------------------------;
#                 ReadSector(....)                                       ;
#------------------------------------------------------------------------;
#use the BIOS int 13h							 ;
#------------------------------------------------------------------------;
#reset the floppy 							 ;
#  ah=00h,								 ;
#  dl=DRIVER serial number(0:A)						 ;
#------------------------------------------------------------------------;
#get the data from the floppy,						 ;
#and put it in the memory buffer according to the pointer es:bx		 ;
#  ah=02h,								 ;
#  al=the sector number wanted,						 ;
#  ch=cylinder(track) serial number,		 			 ;
#  cl=start sector serial number,					 ;
#  dh=magnetic head serial number,					 ;
#  dl=DRIVER serial number(0:A,00H-7FH:floppy,80H-0FFH:Hard Disk),	 ;
#  es:bx->data buffer							 ;
#------------------------------------------------------------------------;
#the result:                                                             ;
#  CF=0 succeed ->AH=00H,AL=the sector number read                       ;
## else ->AL=the state code                                              ;
#------------------------------------------------------------------------;
#the 1.44MB floppy has two sides(megnetic head 0 and 1),each side has 80 ;
#(0-79) tracks,each track has 18 sectors(1-18).				 ;
#          The sector serial number      				 ;
#          ----------------------------=the quotient Q,the remainder R;  ;
#           sector number per track(18) 				 ;
#the cylinder serial number  =  Q>>1					 ;
#the magnetic head           =  Q&1					 ;
#the start sector            =  R+1					 ;
#------------------------------------------------------------------------;

#------------------------------------------------------------------------;
#    void  ReadSector(start sector 2byte,sector number 2byte,es,bx)      ;
#    !!!There is something wrong with the following function.Because the ;
#    int $0x13 ah=0x2 can read only one track ,it means it can read as   ;
#    many as 18 sectors.However we don't come across the problem so far. ;
#------------------------------------------------------------------------;
ReadSector:
  pushw %bp
  movw  %sp,%bp
  pusha
  pushw %es
  movw  4(%bp),%ax
  movb  $SECTORNUMBERPERTRACK,%bl
  divb  %bl
  movb  %al,%ch
  movb  %al,%dh
  movb  %ah,%cl
  shrb  %ch
  andb  $1,%dh
  addb  $1,%cl
  movb  $0x02,%ah
  movb  6(%bp),%al
  movw  8(%bp),%bx
  movw  %bx,%es
  movw  10(%bp),%bx
  movb  $DRIVER,%dl
LABEL_GOONREAD:
  int   $0x13
  jc LABEL_GOONREAD
  popw  %es
  popa
  popw  %bp
  ret
#--------------------------------------------------------------------;
#                   void PutOneByteNumber(U2B)                              ;
#--------------------------------------------------------------------;
PutOneByteNumber:
   pushw  %bp
   movw   %sp,%bp
   pusha   
   movb   4(%bp),%al
   movb   $0x0F,%ah
   movw   %ax,%bx
   shrb   $4,%bl
   cmp    $9 ,%bl
   ja     LABEL_ABOVENINE
   addb   $48,%bl
   jmp    LABEL_NUMBERSHOW
LABEL_ABOVENINE:
   addb   $55,%bl
LABEL_NUMBERSHOW:
   pushw  %bx
   call PutAttributeChar
   addw  $2,%sp
   andb  $0x0F,%al
   cmpb   $9,%al
   ja    LABEL_LOWABOVE
   addb  $48,%al
   jmp  LABEL_LOWSHOW
LABEL_LOWABOVE:
   addb  $55,%al
LABEL_LOWSHOW:
   push  %ax
   call PutAttributeChar
   addw $2,%sp
   popa
   popw   %bp
   ret
#-----------------------------------------;
# void PutTwoBytesNumber(U2B)             ;
#-----------------------------------------;
PutTwoBytesNumber:
   pushw  %bp
   movw   %sp,%bp
   pusha   
   movw   4(%bp),%ax
   movb  $0x0F,%bh
   movb   %ah,%bl
   pushw  %bx
   call   PutOneByteNumber
   popw   %bx
   movb   %al,%bl
   pushw  %bx
   call   PutOneByteNumber
   popw   %bx
   popa
   popw   %bp
   ret
#--------------------------------------------------------------------;
#       void PutFourBytesNumber(U4B)                                 ;
#--------------------------------------------------------------------;
PutFourBytesNumber:
   pushw  %bp
   movw   %sp,%bp
   pusha
   movl  4(%bp),%eax
   movw  %ax,%bx
   shrl  $16,%eax
   pushw %ax
   call  PutTwoBytesNumber
   popw  %ax
   pushw  %bx
   call  PutTwoBytesNumber
   popw  %bx
   popa
   popw  %bp
   ret
#--------------------------------------------------------------------;
#       void PutAttributeChar(U1B character,U1B attribute)           ;
#--------------------------------------------------------------------;
PutAttributeChar:
   pushw  %bp
   movw   %sp,%bp
   pusha   
   movw   4(%bp),%ax
   #in the ax,the al contains the char,and the ah contains the attribute.
   #So we put the ax to the display buffer ,
   #the even address needs the char,we put the ax directly .It's all ok.
   movw   cgashowoffset,%bx
   cmp    $4000,%bx
   jb     LABEL_PLACECHAR
   movw   $0,cgashowoffset
   movw   $0,%bx
LABEL_PLACECHAR:
   movw   %ax,%gs:(%bx)
   addw   $2 ,cgashowoffset
   popa
   popw   %bp
   ret
#-------------------------------------------------------------------;
#                void ClearScreen()                                 ;
#-------------------------------------------------------------------;
ClearScreen:
   pushw  %bp 
   movw   %sp,%bp
   pusha
   movw   $0x0020,%ax
   movw   $2000,%cx
   pushw  %ax
LABEL_GOONCLEAR:
   call  PutAttributeChar
   subw  $1,%cx
   cmpw  $0,%cx
   ja    LABEL_GOONCLEAR
   addw  $2,%sp
   popa
   popw   %bp
   ret
#-------------------------------------------------------------------;
#                void PutReturn()                                   ;
#-------------------------------------------------------------------;
PutReturn:
   pushw  %bp 
   movw   %sp,%bp
   pusha
   movw   cgashowoffset,%ax
   movb   $160,%bl
   divb   %bl
   addb   $1,%al
   cmp    $25,%al
   jb     LABEL_RETURN
   movb   $0,%al
LABEL_RETURN:
   movb   $0,%ah
   mulb   %bl
   movw   %ax,cgashowoffset
   popa
   popw   %bp
   ret
#-------------------------------------------------------------------;
#  void  SetXY(U1B X,U1B Y)                                         ;
#  X:0-24   Y:0-79                                                  ;
#-------------------------------------------------------------------;
SetXY:
   pushw   %bp
   movw    %sp,%bp
   pusha
   movw  4(%bp),%ax
   #al:X,ah:Y
   cmpb  $24,%al
   ja    LABEL_SETXYEND
   cmpb  $79,%ah
   ja    LABEL_SETXYEND
   movb  %ah,%cl
   movb  $0,%ah
   movb  $160,%bl
   mulb  %bl
   movw  %ax,%dx
   movw  $0,%ax
   movb  %cl,%al
   movb  $2,%bl
   mulb  %bl
   addw  %dx,%ax
   movw  %ax,cgashowoffset
LABEL_SETXYEND:
   popa
   popw    %bp
   ret
#-------------------------------------------------------------------;
#  void PutAttributeString(U4B position,U2B attribute,U2B length)   ;
#-------------------------------------------------------------------;
PutAttributeString:
   pushw  %bp
   movw   %sp,%bp
   pusha   
   #get the position
   movl   4(%bp),%edx
   #get the attribute
   movw   8(%bp),%bx
   movb   %bl,%ah
   movl   $0,%ebx
   #get the length
   movw   10(%bp),%cx
   #get and call
LABEL_GOONSHOW:
   cmp    %cx,%bx
   jae    LABEL_STRINGOVER
   addl   %ebx,%edx
   movb   (%edx),%al
   subl   %ebx,%edx
   pushw  %ax
   call   PutAttributeChar
   addw   $2,%sp
   addw   $1,%bx
   jmp    LABEL_GOONSHOW
LABEL_STRINGOVER:
   popa
   popw   %bp
   ret
#---------------------------------------------;
#           void KillMotor()                  ;
#---------------------------------------------;
KillMotor:
   pushw  %bp
   movw   %sp,%bp
   pusha
   movw   $0x03F2,%dx
   movb   $0,%al
   outb   %al,%dx
   popa
   popw   %bp 
   ret
#---------------------------------------------;
#           void GetMemorySize()              ;
#---------------------------------------------;
GetMemorySize:
   pushw  %bp
   movw   %sp,%bp
   pusha 
   movl   $0,%ebx
   movw   $MEMORYCHECKBUFFERSEGMENT,%ax
   movw   %ax,%es
   movw   $MEMORYCHECKBUFFEROFFSET,%di
LABEL_MEMORYCHECK:
   movl   $0x0E820,%eax
   movl   $20,%ecx
   movl   $0x534D4150,%edx
   int    $0x15
   jc     LABEL_MEMORYWRONG
   addw   $1,ardsnumber
   addw   %cx,%di
   cmpl   $0,%ebx
   jne    LABEL_MEMORYCHECK
   jmp    LABEL_MEMORYCHECKEND
LABEL_MEMORYWRONG:
   movw   $0,ardsnumber
LABEL_MEMORYCHECKEND:
   popa
   popw   %bp
   ret
#---------------------------------------------------------------------------;
#---------------------------------------------------------------------------;
#---------------------------------------------------------------------------;
#   In the transition between the real mode and the protect mode.           ;
#---------------------------------------------------------------------------;
#---------------------------------------------------------------------------;
#---------------------------------------------------------------------------;
LABEL_GOTOPROTECTMODE:
   lgdt  gdtpointer
   cli
   inb   $0x92,%al
   orb   $0b00000010,%al
   outb  %al,$0x92
   movl  %cr0,%eax
   orl   $1,%eax
   movl  %eax,%cr0
   ljmpl $SELECTORKERNELCODE,$LABEL_MOVEKERNEL
   jmp .   #This sentence is used to avoid losing control .
#--------------------------------------------------------------------------;
#  The next is protect mode.                                               ;
#--------------------------------------------------------------------------;
#The code uses 32 bits 
.code32
LABEL_MOVEKERNEL:
#  Init the segment registers.
   movw  $SELECTORKERNELDATA,%ax
   movw  %ax,%ds
   movw  %ax,%es
   movw  %ax,%fs
   movw  %ax,%ss
   movw  $SELECTORCGA,%ax
   movw  %ax,%gs
#  Show the protect mode message.
   call  DisplayReturn
   pushw $44
   pushw $0x0F
   pushl $loaderprotectmodemessage
   call  DisplayAttributeString
   addl  $8,%esp
 #  movl   $KernelParametersShowPosition,%eax
 #  movl   $0,%ebx
 #  movw   cgashowoffset,%bx
 #  movl   %ebx,(%eax)
#It's time to move the kernel to the 0x100000-?
#                    \(^oo^)/
   movl  $KernelSize,%ecx
   movl  $KERNELFIRSTFULLADDRESS,%esi
   movl  $KERNELSECONDFULLADDRESS,%edi
   cld
   rep movsb
#OK,go to the kernel.
#\(^oo^)/\(^oo^)/\(^oo^)/\(^oo^)/\(^oo^)/
   ljmpl $SELECTORKERNELCODE,$KERNELSECONDFULLADDRESS
   jmp .
#--------------------------------------------------------------------;
#       void DisplayAttributeChar(U1B character,U1B attribute)       ;
#--------------------------------------------------------------------;
DisplayAttributeChar:
   pushl  %ebp
   movl   %esp,%ebp
   pushw %ax
   pushw %bx
   movw   8(%ebp),%ax
   #in the ax,the al contains the char,and the ah contains the attribute.
   #So we put the ax to the display buffer ,
   #the even address needs the char,we put the ax directly .It's all ok.
   movw   cgashowoffset,%bx
   cmp    $4000,%bx
   jb     LABEL_DISPLAYCHAR
   movw   $0,cgashowoffset
   movw   $0,%bx
LABEL_DISPLAYCHAR:
   movw   %ax,%gs:(%bx)
   addw   $2 ,cgashowoffset
   popw %bx
   popw %ax
   popl   %ebp
   ret
#-------------------------------------------------------------------;
# void DisplayAttributeString(U4B position,U2B attribute,U2B length);
#-------------------------------------------------------------------;
DisplayAttributeString:
   pushl  %ebp
   movl   %esp,%ebp
   pushl  %eax
   pushl  %ebx
   pushl  %ecx
   pushl  %edx
   #get the position
   movl   8(%ebp),%edx
   #get the attribute
   movw   12(%ebp),%bx
   movb   %bl,%ah
   movl   $0,%ebx
   #get the length
   movw   14(%ebp),%cx
   #get and call
LABEL_GOONDISPLAY:
   cmp    %cx,%bx
   jae    LABEL_DISPLAYOVER
   addl   %ebx,%edx
   movb   (%edx),%al
   subl   %ebx,%edx
   pushw  %ax
   call   DisplayAttributeChar
   addw   $2,%sp
   addw   $1,%bx
   jmp    LABEL_GOONDISPLAY
LABEL_DISPLAYOVER:
   popl   %edx
   popl   %ecx
   popl   %ebx
   popl   %eax
   popl   %ebp
   ret
#-------------------------------------------------------------------;
#                void DisplayReturn()                                   ;
#-------------------------------------------------------------------;
DisplayReturn:
   pushl  %ebp 
   movl   %esp,%ebp
   pushl  %eax
   pushl  %ebx
   pushl  %ecx
   pushl  %edx
   movw   cgashowoffset,%ax
   movb   $160,%bl
   divb   %bl
   addb   $1,%al
   cmp    $25,%al
   jb     LABEL_DISPLAYRETURN
   movb   $0,%al
LABEL_DISPLAYRETURN:
   movb   $0,%ah
   mulb   %bl
   movw   %ax,cgashowoffset
   popl   %edx
   popl   %ecx
   popl   %ebx
   popl   %eax
   popl   %ebp
   ret
